查看原文
其他

网络通信与治理,谁更在行?Envoy 和 Nginx 对比 | 附本月初送书活动

刘俊海 Linux云计算网络 2021-12-21

文末送书,文末送书

Nginx 是 Envoy 出现之前网络通信中间件领域非常有代表性的开源系统,功能强大,性能出色,扩展性很强,已经形成了强大的生态,成为 HTTP 流量管理领域事实上的标杆。Envoy 作为后起之秀,虽然定位和目标上与 Nginx 有不少差异,但架构设计层面, Envoy 和 Nginx 都有很多的可取之处。

下面会从功能定位、整体网络模型、连接处理、请求解析、插件机制等维度,对 Envoy 和 Nginx 进行详细剖析和比较,通过与 Nginx 功能和架构层面的全方位对比,大家也可以对 Envoy 的架构设计有更立体的认识。

1. 功能与定位

Nginx 最核心的功能是 Web 服务器和反向代理服务器, Web 服务器完成对 HTTP 请求协议的解析和以 HTTP 协议格式响应请求、缓存、日志处理这些基本 Web 服务器功能;反向代理服务器完成对请求的转发、负载均衡、鉴权、限流、缓存、日志处理等代理常用功能。

除了对 Nginx 协议的支持外, Nginx 还支持普通的 TCP、UDP 反向代理功能,同时以 stream 方式支持通用的基于 4 层协议的反向代理,比如 MySQL 代理、Memcached 代理等。

Envoy 的目标比较远大,定位是透明接管微服务之间的通信流量,将通信和服务治理功能从微服务中解耦,通过 Envoy 可以方便地增加对自定义协议的支持。

概括起来, Nginx 的关键词是 Web 服务器和反向代理, Envoy 是透明接管流量,更加体现对流量的控制和掌控力。另外,从使用方式上看,微服务对 Nginx 是显式调用,通过 Nginx 完成负载均衡等相关功能,对 Envoy 是隐式调用,业务微服务不需要感知 Envoy 的存在,和使用 Envoy 使用相同的方式进行通信,只不过不再需要关注通信和链路治理的细节。

2. 网络模型

网络模型上, Nginx 采用的是经典的多进程架构,由 master 进程和worker 进程组成。其中,master 进程负责对 worker 进程进行管理,具体包含监控 worker 进程的运行状态,根据外部输入的一些管理命令向 worker 进程发送处理信号以及 worker 进程退出时启动新的 worker 进程。worker 进程负责处理各种网络事件,各个 worker 进程之间相互独立,一同竞争来自客户端的新的连接和请求,为了保证请求处理的高效,一个请求处理的全部过程在同一个 worker 进程中。worker 进程的个数推荐配置为与当前环境的 CPU 核数相同。

自从 Nginx 诞生以来,一直使用上述经典的多进程架构。这种架构下,请求处理过程中如果遇到特别耗时的操作,比如磁盘访问、第三方服务同步访问等,会导致处理该请求的进程被夯住,不仅 CPU 资源没有得到充分利用,夯住时间比较长时不仅会影响当前请求,严重时会导致本进程的待处理请求大量超时。为了解决这种问题, Nginx 从 1.7.11 版本开始引入了线程池的概念,如果遇到耗时特别长的逻辑,可以增加线程池配置,放到线程池中进行处理。线程池机制的引入对 Nginx 架构来说是个很好的补充,通过针对性地解决耗时特别长的一些阻塞场景,使得 Nginx 的性能达到一个新的高度。

和 Nginx 不同, Envoy 采用了多线程的网络架构, Envoy 一般会根据当前 CPU 核数创建相同个数的 worker 线程,所有 worker 线程同时对 Envoy 配置的监听器进行监听,接受新的连接,为每个新连接实例化相应的过滤器处理链,处理该连接上的所有请求。和 Nginx 类似, Envoy 的每个请求的处理全流程都在同一个线程下进行。

从上面的分析看, Envoy 和 Nginx 的网络处理方式大体类似。这两种方式都是全异步的编程模式,所有的操作都是异步进行,每个执行上下文使用一个单独的事件调度器,对该执行上下文的异步事件进行调度和触发,只是承载网络的执行上下文有差异, Nginx 通过多进程的方式承载, Envoy 使用的是多线程方式。

Nginx 通过线程池的方式,从设计上解决了异步编程中的阻塞问题,但仍然没有从根本上解决这个问题,如果遇到设计或者代码层面没有注意到的问题场景,仍然会出现因为当前请求阻塞导致后续等待的请求得不到处理而超时的现象。由于都是全异步的编程模式, Envoy 也会遇到同样的问题,不过 Envoy 开始尝试着进行解决,具体的解决方式是:为每个 worker 线程分别设置一个看门狗,并通过定时器定期更新本线程看门狗的最新更新时间,主线程会监控各个 worker 线程看门狗一段时间内是否有更新,如果超过一段时间没有更新,可以认为该线程的看门狗定时更新操作得不到执行的机会,从而推断出这个线程当前已经夯住,无法处理请求消息。Envoy 通过这种机制可以检测出 worker 线程是否被长时间阻塞住,在此机制的基础上,后续可以增加相应的处理(比如将待处理请求移到其他线程,然后把该线程杀掉),可以从机制上解决工作线程被阻塞的问题。

3. 连接处理

Nginx 通过 worker_connections 参数来控制每个 worker 能够建立的最大连接数,从 Nginx 网络模型可以看出,客户端连接到来时,所有空闲的进程都会去竞争这个新连接。这种竞争如果导致某个进程得到的新连接比较多,同时该进程的空闲连接也会很快用完,如果不进行控制,后续该进程获取新连接时会遇到没有空闲连接而丢弃,而有的进程有空闲连接却获取不到新连接。那么直接按照均等的方式将连接分配给各个进程是否可行呢?这种方式其实也是有问题的,不同连接上可能承载的请求 QPS 差异很大,可能会出现两个进程处理相同连接数,但一个特别忙另外一个特别闲的现象,因此为了保证各个工作进程都能够最大限度地提供自己的计算能力,需要对连接进行精细化管理, Nginx 采取的方式是各工作进程根据自身的忙闲程度,动态调整获取新连接的时机,具体实现是:当本进程当前连接数达到最大 worker_connections 的 7/8 时,本 worker 进程不会去试图拿 accept 锁,也不会去处理新连接,这样其他 worker 进程就更有机会去处理监听句柄,建立新连接。而且,由于超时时间的设定,使得没有拿到锁的 worker 进程去拿锁的频率更高,通过这种方式, Nginx 解决了 worker 进程之间的负载均衡问题。

Envoy 也会遇到和 Nginx 类似的负载不均问题, Envoy 当前发展很快,同时需要解决的问题很多, Envoy 社区的人觉得这个问题当前的优先级还不够高,后续会根据具体情况对这个问题进行讨论和解决。

4. 插件机制

Nginx 拥有强大的插件扩展能力,基于 Nginx 的插件扩展机制,业务可以非常方便地完成差异化和个性化定制, Nginx  插件通过模块的方式提供,具体来说, Nginx 主要提供如下几种形式的插件扩展:

1)通过 stream 机制进行协议扩展,比如增加 memcached 协议代理和负载均衡等;

2)以 Handler 方式处理 HTTP 请求;

3)对 HTTP 请求和响应消息进行过滤,比如可以修改和定制消息内容等;

4)访问 Upstream 时的负载均衡,可以提供自定义的负载均衡机制。

对于最成熟的 HTTP 协议来说, Nginx 把整个请求处理过程划分为多个阶段,当前一共有包含读取请求内容、请求地址改写等一共 11 个处理阶段,业务需要在某个阶段进行扩展和定制处理时,只需要挂载该阶段对应的回调函数, Nginx 核心处理 HTTP 请求到这个阶段时,会回调之前注册的回调函数进行处理。

Nginx 对模块的支持总体来说不算灵活, Nginx 模块必须和 Nginx 自身源码一块编译,并且只能在编译期间选择当前支持的模块,不支持运行时进行模块动态选取和加载,大家一直以来吐槽比较多。为了解决这个问题, Nginx 在 1.9.11 版本引入了模块动态加载支持,从此不再需要替换 Nginx 文件即可增加第三方模块扩展。Nginx 也支持 Lua 扩展,利用 Lua 语言的简单易用和强大的协程机制,可以非常方便地实现很多扩展机制,并且性能也能够基本满足需求。

Envoy 也提供了强大的插件扩展机制,当前使用最多的地方是监听过滤插件和网络处理过滤插件。和 Nginx 相比, Envoy 网络插件定位在协议层面,以 HTTP 协议为例, Envoy 并没有那么细粒度的插件扩展机制,如果想对 Envoy 的 HTTP 协议处理进行扩展,当前并没有提供特别多的扩展点。

Envoy 的插件当前采用的是静态注册的方式,插件代码和 Envoy 代码一块进行编译,和 Nginx 不同, Envoy 从最开始就支持插件的动态加载, Envoy 通过独特的 XDS API 设计,可以随时对 Envoy 的XDS插件进行定制修改,Istio 将修改后的 XDS 配置通过 Grpc 的方式推送给  Envoy 动态加载和生效。

此外,当前 Envoy 社区和 Cilium 社区一块探索利用,利用 eBPF 提供的用户态网络定制能力,对 Envoy 的流量进行精细化的管理和扩展定制。Cilium 从 1.3 版本开始,引入了 Envoy 的 Go 扩展,通过 Go 扩展实现 Filter 插件向 Envoy 注册,主要实现的还是 OnData() 函数,当 Envoy 接收到流量时,就会调用插件的 OnData 函数进行处理。

Envoy 在 Lua 扩展支持方面也进行了一些探索性的工作,当前已经试验性地支持使用 Lua 脚本对 HTTP 请求进行过滤和调整。Lua 脚本 HTTP 过滤器当前仍处于实验阶段,不建议直接在生产环境中使用,后续待验证成熟后才能在生产环境使用。成熟后可以在更多的场景下通过 Lua 脚本机制增强 Envoy 的扩展性。

限于篇幅,对配置管理、内存管理、部署与运维、观测与诊断方面的对比分析感兴趣的同学,可以参见《Service Mesh微服务架构设计》。

以上内容摘自《Service Mesh微服务架构设计》一书,经出版方授权发布。

作者简介 刘俊海,好未来高级架构师,曾在滴滴、百度等知名互联网公司任职,超过 8 年 C/C++ 开发和架构设计经验;精通服务框架和业务高可用技术,多年亿级流量环境下高并发和高可用实战经验,精通微服务架构和微服务基础设施,近期关注 Service Mesh。

接下来就是本月的无套路送书啦,我知道有小伙伴已经等不及了。

3 本《Service Mesh微服务架构设计》由 【机械工业出版社华章公司】 赞助,在此表示感谢。

送书规则:留言区用一句话总结微服务的优势 or 劣势或者说说你对微服务的理解。

小编我会挑选 3 位幸运读者,《Service Mesh微服务架构设计》包邮到家(平时分享转发、点赞较多的小伙伴获奖概率更大哦~)

截止时间到明天(2019.12.7)下午18:00。大家多多参与,每个人都有机会哦~

未获奖的小伙伴也可以点击下方的小程序购买哦。



后台回复“加群”,带你进入高手如云交流群


推荐阅读:

K8s中的多容器Pod和Pod内容器间通信

中国IPv6技术发展状况白皮书(附下载)

主流全力推K8S,K8S成混合云互通标准

工作中 99% 能用到的 Git 命令

你真的会调试 Linux 内核故障吗?

大白话讲解技术专业用语

我是一个CPU:这个世界慢!死!了!

手把手教你在CentOS上搭建Kubernetes集群

Linux 系统结构详解

IT架构师绝对不能错过的34张史上最全技术知识图谱

滴滴30K月薪笔试题

8 年 SDN 之路的回顾总结

2019年最新最全运维技能图谱,必看!


喜欢,就给我一个“在看”



10T 技术资源大放送!包括但不限于:云计算、虚拟化、微服务、大数据、网络、Linux、Docker、Kubernetes、Python、Go、C/C++、Shell、PPT 等。在公众号内回复「1024」,即可免费获取!!

: . Video Mini Program Like ,轻点两下取消赞 Wow ,轻点两下取消在看

您可能也对以下帖子感兴趣

文章有问题?点此查看未经处理的缓存